<?php

namespace app\admin\service\user;

use app\admin\service\BaseService;
use app\common\constant\OperateLogFieldMap;
use app\common\model\common\OperateLog;
use app\common\model\user\User;
use app\common\utils\FileUtil;
use app\common\utils\MysqlUtils;
use app\common\utils\MyTools;
use Overtrue\Pinyin\Pinyin;
use think\facade\Cache;
use think\facade\Config;
use think\facade\Queue;

class UserService extends BaseService
{
    public static function insertMockData()
    {
        $count = User::getDataCount();
        if ($count >= 1000) {
            throw new \Exception("当前用户数据总数{$count}, 已经足够测试用了");
        }

        $pinyin = new Pinyin();
        for ($i = 0; $i <= 1000; $i++) {
            $nickname = MyTools::getChineseRandomName();
            $add_data = [
                'username' => str_replace(' ', '', $pinyin->sentence($nickname)),
                'mobile' => '1' . rand(300000, 999999),
                'nickname' => $nickname,
                'avatar' => 'https://profile-avatar.csdnimg.cn/default.jpg',
                'last_login_time' => echoNowDate(),
            ];
            User::insert($add_data);
        }
        return true;
    }

    /**
     * 获取用户列表
     * @param $params array
     * @param $is_export bool 是否导出Excel
     * @param $is_from_queue bool 是否是从队列操作
     * @return array
     * @throws \Exception
     */
    public static function getUserList(array $params, bool $is_export = false, bool $is_from_queue = false)
    {
        //查询列表数据
        if ($is_export) {
            unset($params['page']);
            unset($params['page_size']);
        }
        list($count, $list) = User::getCountAndList($params);
        if (empty($list)) {
            return [
                'count' => $count,
                'list' => $list,
            ];
        }

        //格式化列表数据
        foreach ($list as &$v) {
            unset($v['password']);
            unset($v['is_deleted']);

            //针对可能出现二维结构的情况模拟
            $v['time'] = [
                'last_login_time' => $v['last_login_time'],
                'add_time' => $v['add_time'],
                'update_time' => $v['update_time'],
            ];
            unset($v['last_login_time']);
            unset($v['add_time']);
            unset($v['update_time']);

            //todo 更多格式化处理...
        }

        //导出Excel
        if ($is_export) {
            //如果超过设定的最大直接导出条数,或者需要导出附件("export":"data_and_attachment"),则通过队列异步导出
            if (!$is_from_queue && (count($list) > User::MAX_EXPORT_COUNT || $params['export'] == 'data_and_attachment')) {
                self::exportUserListDataByQueue($list, $params);
            } else {
                return self::exportUserListData($list, $params);
            }
        }

        //返回列表数据
        return [
            'count' => $count,
            'list' => $list,
        ];
    }

    /**
     * 写入队列,异步导出用户列表数据
     * @param array $list
     * @param array $params
     * @throws \Exception
     */
    public static function exportUserListDataByQueue(array $list, array $params): bool
    {
        //判断当前排队情况
        $jobQueueName = "exportUserDataQueue";
        $cache_key = "{queues:$jobQueueName}";
        $cache_data = Cache::store('redis')->handler()->lrange($cache_key, 0, -1);
        $cache_count = count($cache_data);
        if ($cache_count >= 10) {
            throw new \Exception('当前导出队列排队已达到10个，请稍后再试！');
        }

        //写入队列
        $jobHandlerClassName = 'app\job\user\UserExportConsumer';
        $queue_data = [
            'time' => time(),
            'params' => $params,
            'count' => count($list),
            'operate_user_id' => 1, //操作人的id
        ];
        $isPushed = Queue::push($jobHandlerClassName, $queue_data, $jobQueueName);
        if (!$isPushed) {
            throw new \Exception('导出数据过大,写入队列失败,请联系管理员');
        } else {
            throw new \Exception('导出数据过大,稍后将通过队列导出');
        }
    }

    /**
     * 直接导出用户列表数据
     * @param $list array
     * @param $params array
     * @return array
     * @throws \Exception
     */
    public static function exportUserListData(array $list, array $params): array
    {
        //针对需要导出的数据再次格式化字段
        foreach ($list as &$v) {
            $v['status'] = $v['status'] == User::STATUS_NORMAL ? '正常' : '禁用';
        }

        //设置导出的字段和表头
        $field_map = [
            "id" => "ID",
            "username" => "用户名",
            "mobile" => "手机号",
            "nickname" => "昵称",
            "status" => "状态",
            //针对二维模型导出的字段定义
            "time.last_login_time" => "最后登录时间",
            "time.add_time" => "添加时间",
            "time.update_time" => "修改时间",
        ];

        //执行导出Excel
        $file_root = root_path() . 'public'; //根目录
        $file_folder = 'export/' . date("Y/m", time()); //相对路径
        $file_path = $file_root . '/' . $file_folder; //绝对路径
        $file_title = '用户数据导出-' . time();
        $output_file_name = FileUtil::outputExcel($list, $field_map, $file_path, $file_title);

        //导出用户头像附件并生成压缩包
        if ($params['export'] == 'data_and_attachment') {
            $zip_file_path = $file_path . '/' . $file_title;
            if (!file_exists($zip_file_path)) {
                mkdir($zip_file_path, 0777, true);
            }
            rename($file_path . '/' . $output_file_name, $zip_file_path . '/' . $output_file_name);
            foreach ($list as $value) {
                $file_name = 'userid-' . $value['id'] . '.jpg';
                FileUtil::downloadRemoteFile($value['avatar'], $zip_file_path . '/attachment/' . $file_name);
            }
            FileUtil::createZipFile($zip_file_path);
            $output_file_name = $file_title . '.zip';
        }

        //返回本地HOST的URL
        $file_url = Config::get('app.app_host') . '/' . $file_folder . '/' . $output_file_name;

        //todo 上传到OSS...
        /*
        try {
            $oss = new Oss();
            $file_url = $oss->upload($output_file_name, $file_path . '/' . $output_file_name);
        } catch (\Exception $e) {
            MyLog::record()->error($e->getMessage(), 'Oss::upload/error');
            throw new \Exception("上传附件到OSS失败");
        }
        */

        return [
            'file_url' => $file_url,
        ];
    }

    /**
     * 更新用户数据
     * @param $params array
     * @return mixed
     * @throws \Exception
     */
    public static function updateUserData(array $params): bool
    {
        $id = $params['id'];
        User::dataConn()->filterParams($params);
        //获取修改前的数据
        $old_user_info = User::getDataInfoById($id);
        //插入更新记录
        list($before_data, $after_data) = MysqlUtils::getUpdateDataDiff($old_user_info, $params);
        if (!empty($before_data) || !empty($after_data)) {
            OperateLog::addOperateLog(OperateLogFieldMap::CATEGORY_USER, $id, $before_data, $after_data);
        }
        return User::updateDataById($params, $id);
    }


}